const { isPlainObject } = require('lodash');
const utils = require('./lib/utils')
const axios = require('axios');
const mysqlConnPool = require('./lib/mysqlConn');

const options = {
    url: 'https://xhzw.market.alicloudapi.com/isp',
    method: "POST",
    headers: { 'Authorization': 'APPCODE 0959a450496a45fe825a755b1e5f3da4' },
}

const areaOptions = {
    url: 'https://kzlocation.market.alicloudapi.com/api-mall/api/mobile_location/query',
    method: "POST",
    headers: { 'Authorization': 'APPCODE 0959a450496a45fe825a755b1e5f3da4' },
}

const ispCodeMap = {
    '移动': 'gmcc',
    '联通': 'unicom',
    '电信': 'cdma'
}

const areaCodeMap = {
    "北京": "bj",
    "上海": "sh",
    "天津": "tj",
    "重庆": "cq",
    "香港": "xg",
    "澳门": "am",
    "安徽": "ah",
    "福建": "fj",
    "广东": "gd",
    "广西": "gx",
    "贵州": "gz",
    "甘肃": "gs",
    "海南": "hain",
    "河北": "he",
    "河南": "hn",
    "黑龙江": "hlj",
    "湖北": "hb",
    "湖南": "hun",
    "吉林": "jl",
    "江苏": "js",
    "江西": "jx",
    "辽宁": "ln",
    "内蒙古": "nmg",
    "宁夏": "nx",
    "青海": "qh",
    "陕西": "sn",
    "山西": "sx",
    "山东": "sd",
    "四川": "sc",
    "台湾": "tw",
    "西藏": "xz",
    "新疆": "xj",
    "云南": "yn",
    "浙江": "zj"
};

function simplifyProvinceName(fullName) {
    // 定义需要特殊处理的名称（保留简称中的特殊字）
    const specialCases = {
        '内蒙古自治区': '内蒙古',
        '新疆维吾尔自治区': '新疆',
        '西藏自治区': '西藏',
        '广西壮族自治区': '广西',
        '宁夏回族自治区': '宁夏',
        '香港特别行政区': '香港',
        '澳门特别行政区': '澳门',
        '北京市': '北京',
        '上海市': '上海',
        '天津市': '天津',
        '重庆市': '重庆'
    };

    // 先处理特殊情况
    if (specialCases[fullName]) {
        return specialCases[fullName];
    }

    // 通用处理：去除常见后缀（省、自治区、市）
    return fullName.replace(/(省|自治区|市)$/, '');
}

function checkTimeCondition(push_time, try_times) {
    const timeMap = [0, 1, 15, 60, 24 * 60];

    // 如果 push_time 不存在，直接返回 true
    if (!push_time) {
        return true;
    }

    // 确保 try_times 在 timeMap 范围内
    if (try_times < 0 || try_times >= timeMap.length) {
        return false;
    }

    // 获取对应时间间隔（分钟）
    const minutesToAdd = timeMap[try_times];

    // 将 push_time 加上对应分钟数得到新时间
    const newTime = new Date(push_time.getTime() + minutesToAdd * 60 * 1000);

    // 获取当前时间
    const currentTime = new Date();

    // 判断新时间是否早于当前时间
    return newTime < currentTime;
}

function chunkArray(arr, size) {
    const result = [];
    for (let i = 0; i < arr.length; i += size) {
        result.push(arr.slice(i, i + size));
    }
    return result;
}

async function getMobileInfo(mobile) {
    options.params = { mobile }
    try {
        let result = await models.mobileInfo.findOne({ mobile });
        if (!result) {
            result = await mysqlConnPool.getMobileInfo(mobile);
            if (!result) {
                const response = await axios(options)
                
                if (response.data.code == 0) {
                    let { res, Mobile, Area, Init_isp, Now_isp } = response.data.result;
                    let cp = Area.split('-');

                    result = {
                        res,
                        mobile: Mobile,
                        area_p: cp[0],
                        area_c: cp[1],
                        init_isp: Init_isp,
                        now_isp: Now_isp
                    };
                    models.mobileInfo.create(result);
                }
            } else {
                result.now_isp = result.isp;
                result.area_p = simplifyProvinceName(result.area_p);
            }
        }
        return {
            isp: ispCodeMap[result.now_isp],
            district: areaCodeMap[result.area_p]
        }
    } catch (error) {
        console.log(error);
    }
    return { isp: "", district: "" }
}

async function pushReport() {
    log.info('report push task start ...')
    while (true) {
        let cusList = await models.customer.find({ report_url: { $ne: '' } })
        for (let i = 0; i < 120; i++) {
            for (let c of cusList) {
                let q = { cus_id: c.account, try_times: { $lt: 4 }, push_status: { $ne: 1 }, lock: '' };
                const limit = 100;
                let lock = i + c.account + new Date().getTime();
                let update = {
                    lock,
                    type: 1 //获取type 1为push
                }
                // let rows = await models.customerReport.updateMany(q, {$set : update}).limit(c.push_limit || 50);
                // 对 update_time 进行升序排序，然后取前 limit 条记录进行更新
                let rows = await models.customerReport
                    .find(q)
                    .sort({ update_time: 1 })
                    .limit(limit).lean();


                const bulkOps = rows.map(doc => ({
                    updateOne: {
                        filter: { _id: doc._id },
                        update: { $set: update }
                    }
                }));
                // 执行批量更新
                if (bulkOps.length > 0) {
                    await models.customerReport.bulkWrite(bulkOps);
                }

                if (rows.length > 0) {
                    let results = await models.customerReport.find({ lock });
                    log.info(c.account, ' push reports results length = ', results.length)
                    if (c.push_type === 'cainiao') {
                        //菜鸟走特殊接口格式
                        for (let report of results) {
                            try {
                                let body = {
                                    supplier: report.cus_id,
                                    method: 'MD5',
                                    // sendKey: c.password,
                                    timestamp: new Date().getTime(),
                                    requestId: report.ref,
                                    phoneNumber: report.mobile,
                                    sendTime: report.send_date,
                                    reportTime: report.report_date,
                                    success: report.status === 'DELIVRD',
                                    senderId: report.cus_id,
                                    errorCode: report.status,
                                    errorMsg: report.status,
                                    smsSize: report.pieces,
                                    bizId: report.ticket,
                                    extend: report.ext
                                }
                                body.signature = utils.getSignature(body, c.password);

                                let resp = await axios.post(c.report_url, body)
                                if (resp.data.code === 0) {
                                    let sucR = await report.updateOne({ $set: { push_status: 1, push_time: new Date() }, $inc: { try_times: 1 } });
                                    log.info(c.account + ' report push suc:' + sucR.modifiedCount, body.phoneNumber, body.errorCode, body.bizId)
                                } else {
                                    body.resp = resp;
                                    throw body
                                }
                            } catch (body) {
                                let errR = await report.updateOne({ $set: { lock: '', push_status: 2, push_time: new Date() }, $inc: { try_times: 1 } });
                                log.info(c.account + ' report push fail:' + errR.modifiedCount + ' | for : ' + body.resp, body.phoneNumber, body.errorCode, body.bizId)
                            }
                        }
                    } else if (c.push_type === 'hxtx') {
                        let data = results.map(item => {
                            return {
                                appkey: item.cus_id,
                                phone: item.mobile,
                                status: item.status === 'DELIVRD' ? 0 : 2,
                                desc: item.status,
                                uid: item.msg_id,
                                report_time: item.report_date
                            }
                        })
                        try {
                            let resp = await axios.post(c.report_url, data)
                            if (resp.data.code === '00000') {
                                let sucR = await models.customerReport.updateMany({ lock }, { $set: { push_status: 1, push_time: new Date() }, $inc: { try_times: 1 } });
                                log.info(c.account + ' report push suc:' + sucR.modifiedCount, data)
                            } else {
                                throw resp.data
                            }
                        } catch (err) {
                            let errR = await models.customerReport.updateMany({ lock }, { $set: { lock: '', push_status: 2, push_time: new Date() }, $inc: { try_times: 1 } });
                            log.info(c.account + ' report push fail:' + errR.modifiedCount + ' | for : ' + err, data)
                        }
                    } else if (c.push_type === 'wz') {
                        //微众银行推送逻辑
                        try {
                            let retBody = [];
                            for (const item of results) {
                                const canPush = checkTimeCondition(item.push_time, item.try_times);
                                if (!canPush) {
                                    await item.updateOne({ $set: { lock: '', update_time: new Date() } });
                                    continue;
                                }
                                
                                let mobileInfo = await getMobileInfo(item.mobile);
                                for (i = 0; i < item.pieces; i++) {
                                    retBody.push({
                                        receiveTime: item.report_date,
                                        mobile: item.mobile,
                                        code: item.status,
                                        errMsg: item.desc,
                                        description: item.desc,
                                        messageId: item.ticket,
                                        smsId: `${item.ticket}-${i}`,
                                        session: item.ref,
                                        sendNo: '10690' + item.ext,
                                        isp: mobileInfo.isp,
                                        district: mobileInfo.district,
                                        smsType: '1',
                                        upgradeTemplateId: '',
                                        scene: '1'
                                    })
                                }
                            }
                            //将resultBody拆成10个一段。推送给客户
                            let pushArray = chunkArray(retBody, c.push_limit || 10);
                            for (let data of pushArray) {
                                const msgIds = data.map(i => i.messageId)
                                try {
                                    let resp = await axios.post(c.report_url, data)

                                    if (resp.data.code == 1) {
                                        let errR = await models.customerReport.updateMany({ lock, ticket: { $in: msgIds } }, { $set: { lock: '', push_status: 2, push_time: new Date() }, $inc: { try_times: 1 } });
                                        log.info(c.account + ' report push fail:' + errR.modifiedCount + ' | for : ', resp.data, data)
                                    } else if (resp.data.code == 0) {
                                        let sucR = await models.customerReport.updateMany({ lock, ticket: { $in: msgIds } }, { $set: { push_status: 1, push_time: new Date() }, $inc: { try_times: 1 } });
                                        log.info(c.account + ' report push suc:' + sucR.modifiedCount + JSON.stringify(data), resp.data)
                                    } else {
                                        //其他错误没，失败不重推
                                        throw new Error(JSON.stringify(resp.data));
                                    }
                                } catch (err) {
                                    let errR2 = await models.customerReport.updateMany({ lock, ticket: { $in: msgIds } }, { $set: { lock: '', push_status: 2, push_time: new Date() }, $inc: { try_times: 1 } });
                                    log.info(c.account + ' report push fail:' + errR2.modifiedCount + ' | for : ', data, err.message)
                                }
                            }
                        } catch (sysErr) {
                            log.error(sysErr)
                        }

                    } else {
                        //iqiyi 走默认推送格式
                        results = results.map(r => {
                            return `${r.ticket},${r.mobile},${r.status},${r.report_date},${r.send_date},${r.pieces},${r.ext},${r.msg_id},${r.ref},${r.iso_code}`
                        });
                        let reportStr = results.join(';')
                        try {
                            let resp = await axios.post(c.report_url, { report: reportStr }, { headers: { "Content-Type": "application/x-www-form-urlencoded" } })
                            if (resp.data === 'success') {
                                let sucR = await models.customerReport.updateMany({ lock }, { $set: { push_status: 1, push_time: new Date() }, $inc: { try_times: 1 } });
                                log.info(c.account + ' report push suc:' + sucR.modifiedCount, reportStr)
                            } else {
                                throw resp.data
                            }
                        } catch (err) {
                            let errR = await models.customerReport.updateMany({ lock }, { $set: { lock: '', push_status: 2, push_time: new Date() }, $inc: { try_times: 1 } });
                            log.info(c.account + ' report push fail:' + errR.modifiedCount + ' | for : ' + err, reportStr)
                        }
                    }
                }
            }
            await utils.sleep(500);
        }
    }
    log.info('report push task stop ...')
}

pushReport();
